package com.spzx.channel.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.spzx.channel.domain.ItemVo;
import com.spzx.channel.service.ItemService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.utils.uuid.UUID;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.domain.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.cache.configuration.Factory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/*
调用关系：channel--》api-product-->spzx-product
 */
@Service
public class ItemServiceImpl implements ItemService {
    @Autowired
    RemoteProductService remoteProductService;//这里有误报
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    ThreadPoolExecutor threadPoolExecutor;

    @Override
    public ItemVo itemChache(Long skuId) throws InterruptedException {
        long start = System.currentTimeMillis();
        //数据key
        String dataKey = "channel:item:" + skuId;
        //锁key
        String lockKey = "channel:item:lock:" + skuId;
        //远程调用product模块,封装item对象
        ItemVo itemVo = new ItemVo();
        //先查缓存
        itemVo = (ItemVo) redisTemplate.opsForValue().get(dataKey);
        //缓存没数据
        if (itemVo == null) {
            //分布式锁
            String lockValue = UUID.randomUUID().toString().replace("-", "");
            Boolean ifLock = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 3, TimeUnit.SECONDS);
            if (ifLock) {
                //拿到锁
                itemVo = item(skuId);//数据方法
                if (itemVo != null) {
                    //同步放缓存
                    //转换
                    Map<String, Object> skuSpecValueMap = itemVo.getSkuSpecValueMap();
                    String skuSpecValueMapJsonString = JSON.toJSONString(skuSpecValueMap);
                    itemVo.setSkuSpecValueMapStr(skuSpecValueMapJsonString);
                    //存值的时候不要skuSpecValueMap字段
                    itemVo.setSkuSpecValueMap(null);
                    redisTemplate.opsForValue().set(dataKey, itemVo);
                } else {
                    //设置一个用来查询的目标，防止时间反复被访问和攻击
                    redisTemplate.opsForValue().set(dataKey, new ItemVo(), 5, TimeUnit.SECONDS);
                }
                //释放锁 lua脚本同时解决两个语句
                String lua = "if redis.call(\"get\",KEYS[1])==ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end";
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                redisScript.setScriptText(lua);
                redisScript.setResultType(Long.class);
                redisTemplate.execute(redisScript, Arrays.asList(lockKey), lockValue);
            } else {
                //没拿到锁，自旋
                Thread.sleep(200);
                return itemChache(skuId);
            }
        }
        //转换回来
        String skuSpecValueMapStr = itemVo.getSkuSpecValueMapStr();
        HashMap<String, Object> map = new HashMap<>();
        HashMap skuSpecValueMap = JSON.parseObject(skuSpecValueMapStr, map.getClass());
        itemVo.setSkuSpecValueMap(skuSpecValueMap);
        long end = System.currentTimeMillis();
        System.out.println("item方法执行时间：" + (end - start) + "毫秒");
        return itemVo;
    }

    //使用异步编程优化
    @Override
    public ItemVo item(Long skuId) {
        //8个
        ItemVo itemVo = new ItemVo();
        //@Schema(description = "商品sku信息")
        //远程调用feign
        CompletableFuture<ProductSku> t_ProductSku = CompletableFuture.supplyAsync(new Supplier<ProductSku>() {
            @Override
            public ProductSku get() {
                R<ProductSku> RproductSku = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
                ProductSku productSku = RproductSku.getData();
                //Long productId = productSku.getProductId();
                itemVo.setProductSku(productSku);
                return productSku;
            }
        }, threadPoolExecutor);

        //@Schema(description = "商品信息")
        CompletableFuture<Product> t_Product = t_ProductSku.thenApplyAsync(new Function<ProductSku, Product>() {
            @Override
            public Product apply(ProductSku productSku) {
                R<Product> productR = remoteProductService.getProduct(productSku.getProductId(), SecurityConstants.INNER);
                Product product = productR.getData();
                itemVo.setProduct(product);
                return product;
            }
        }, threadPoolExecutor);

        //@Schema(description = "最新价格信息")
        CompletableFuture t_SkuPrice = t_Product.thenAcceptAsync(new Consumer<Product>() {
            @Override
            public void accept(Product product) {
                R<SkuPrice> skuPriceR = remoteProductService.getSkuPrice(product.getId(), SecurityConstants.INNER);
                SkuPrice skuPrice = skuPriceR.getData();
                itemVo.setSkuPrice(skuPrice);
            }
        }, threadPoolExecutor);


        //@Schema(description = "商品轮播图列表")
        CompletableFuture t_Urls = t_Product.thenAcceptAsync(new Consumer<Product>() {
            @Override
            public void accept(Product product) {
                String sliderUrls = product.getSliderUrls();
                List<String> sliderUrlList = Arrays.asList(sliderUrls.split(","));
                itemVo.setSliderUrlList(sliderUrlList);
            }
        }, threadPoolExecutor);


        //@Schema(description = "商品详情图片列表")
        CompletableFuture t_ProductDetails = t_Product.thenAcceptAsync(new Consumer<Product>() {
            @Override
            public void accept(Product product) {
                R<ProductDetails> detailsimagesUrlListR = remoteProductService.getDetailsimagesUrlList(product.getId(), SecurityConstants.INNER);
                ProductDetails detailsimagesUrlList = detailsimagesUrlListR.getData();
                String imageUrls = detailsimagesUrlList.getImageUrls();
                itemVo.setDetailsimagesUrlList(Arrays.asList(imageUrls.split(",")));
            }
        }, threadPoolExecutor);


        //@Schema(description = "商品规格信息")
        CompletableFuture t_SpecValue = t_Product.thenAcceptAsync(new Consumer<Product>() {
            @Override
            public void accept(Product product) {
                String specValue = product.getSpecValue();
                JSONArray specValueList = JSON.parseArray(specValue);
                itemVo.setSpecValueList(specValueList);
            }
        }, threadPoolExecutor);


        //@Schema(description = "商品库存信息")
        CompletableFuture t_SkuStock = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                R<SkuStockVo> skuStockVoR = remoteProductService.getSkuStockVo(skuId, SecurityConstants.INNER);
                SkuStockVo skuStockVo = skuStockVoR.getData();
                itemVo.setSkuStockVo(skuStockVo);
            }
        }, threadPoolExecutor);


        //@Schema(description = "商品规格对应商品skuId信息")
        CompletableFuture t_map = t_Product.thenAcceptAsync(new Consumer<Product>() {
            @Override
            public void accept(Product product) {
                Map<String, Object> skuSpecValueMap = remoteProductService.getskuSpecValueMap(product.getId(), SecurityConstants.INNER);
                itemVo.setSkuSpecValueMap(skuSpecValueMap);
            }
        }, threadPoolExecutor);
        CompletableFuture.allOf(t_map, t_SkuStock, t_SpecValue, t_ProductDetails, t_Urls, t_SkuPrice, t_Product, t_ProductSku);
        return itemVo;
    }

//    @Override
//    public ItemVo item(Long skuId) {
//        //8个
//        ItemVo itemVo = new ItemVo();
//        //@Schema(description = "商品sku信息")
//        //远程调用feign
//        R<ProductSku> RproductSku=remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
//        ProductSku productSku = RproductSku.getData();
//        Long productId = productSku.getProductId();
//        //@Schema(description = "商品信息")
//        R<Product> productR=remoteProductService.getProduct(productId,SecurityConstants.INNER);
//        Product product = productR.getData();
//        //@Schema(description = "最新价格信息")
//        R<SkuPrice> skuPriceR=remoteProductService.getSkuPrice(product.getId(),SecurityConstants.INNER);
//        SkuPrice skuPrice = skuPriceR.getData();
//        //@Schema(description = "商品轮播图列表")
//        String sliderUrls = product.getSliderUrls();
//        List<String> sliderUrlList=Arrays.asList(sliderUrls.split(","));
//
//        //@Schema(description = "商品详情图片列表")
//        R<ProductDetails> detailsimagesUrlListR=remoteProductService.getDetailsimagesUrlList(product.getId(),SecurityConstants.INNER);
//        ProductDetails detailsimagesUrlList  = detailsimagesUrlListR.getData();
//
//        //@Schema(description = "商品规格信息")
//        String specValue = product.getSpecValue();
//        JSONArray specValueList= JSON.parseArray(specValue);
//
//        //@Schema(description = "商品库存信息")
//        R<SkuStockVo> skuStockVoR=remoteProductService.getSkuStockVo(skuId,SecurityConstants.INNER);
//        SkuStockVo skuStockVo = skuStockVoR.getData();
//        //@Schema(description = "商品规格对应商品skuId信息")
//        Map<String,Object> skuSpecValueMap=remoteProductService.getskuSpecValueMap(product.getId(),SecurityConstants.INNER);
//
//         itemVo.setProductSku(productSku);
//         itemVo.setProduct(product);
//         itemVo.setSkuPrice(skuPrice);
//         itemVo.setSliderUrlList(sliderUrlList);
//         String imageUrls = detailsimagesUrlList.getImageUrls();
//         itemVo.setDetailsimagesUrlList(Arrays.asList(imageUrls.split(",")));
//         itemVo.setSpecValueList(specValueList);
//         itemVo.setSkuStockVo(skuStockVo);
//         itemVo.setSkuSpecValueMap(skuSpecValueMap);
//
//        return itemVo;
//    }
}
